package com.study.thread.aqs;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/*
    AbstractQueuedSynchronizer（AQS）：aqs是juc并发包锁和其它同步组件实现的基础，让设计锁者/其它同步组件，不必在关心线程的排队，等待和唤醒线程的底层操作，只需要关注实现自己锁即可
        其aqs是抽象的不会直接被使用，推荐子类的静态内部类来继承aqs并重写实现它的未实现的方法，来完成锁的功能，具体可以重写的方法：
            tryAcquire(int arg)：独占式获取到锁返回true，获取不到返回false，其自己实现锁具体的功能，由acquire调用返回true则获取到锁继续运行，否则通过addWaiter(Node)加入阻塞队列
            tryRelease(int arg)：独占式释放当前锁，释放成功返回true，释放失败返回false，具体需有子类实现！
            tryAcquireShread(int arg)：共享式获取锁，返回值大于等于0，获取成功，否则获取失败
            tryReleaseShread(int arg)：共享式释放锁
        底层主要维护了一个FIFO的双向队列(先进先出的队列)，底层还维护了一个state状态的一个volatile的共享变量，底层多数也是调用unsafe的cas操作来实现的原子性，
        ConditionObject：是aqs中的静态内部类，结合锁实现线程之间的同步（和wait/notify）一样，ConditionObject是一个条件变量，每一个锁可以声明多个条件变量，一个条件变量对应一个条件队列（单向链表队列）
            主要用来存放调用了await()方法的被阻塞线程，
        ReentrantLock独占锁中的state：ReentrantLock中代表锁的state状态代表(状态0、没有线程占用、状态>=1、被其它线程占用,当大于1一般来说是重入了)
        ReadWriteReentrantLock读写锁中的state：
        Semaphore信号量中的state：state代表当前可用信号的个数
        CountDownLatch计数器中的state：state代表计数器当前的值

 */

public class Mutex {
    private Sync sync = new Sync();

    public void lock() {
        sync.acquire(1);
    }

    public void unlock() {
        sync.release(1);
    }

    public static final class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            if (Thread.currentThread() == getExclusiveOwnerThread()) {
                int inCount = getState() + arg;
                setState(inCount);
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            if (Thread.currentThread() == getExclusiveOwnerThread()) {
                int count = getState() - arg;
                if (count == 0) {
                    setExclusiveOwnerThread(null);
                    setState(0);
                    return true;
                } else {
                    setState(count);
                }
            }
            return false;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
    }
}
